#include "stdafx.h"
#include "RealIExampleExe.h"

ITypeInfo *ExampleExeTypeInfo;

HRESULT LoadTypeInfo()
{
    HRESULT hr;
    ITypeLib *pTypeLib = NULL;
    hr = LoadRegTypeLib(TLBID_ExampleExe, 1, 0, 0, &pTypeLib);
    if (FAILED(hr)) return hr;
    hr = pTypeLib->GetTypeInfoOfGuid(IID_IExampleExe, &ExampleExeTypeInfo);
    pTypeLib->Release();
    if (FAILED(hr)) return hr;
    ExampleExeTypeInfo->AddRef();
    return S_OK;
}

BOOL CanUnloadNow()
{
    return OutstandingObjects || LockCount ? FALSE : TRUE;
}

RealIExampleExe::RealIExampleExe() : m_count(1), m_str(NULL)
{
}

RealIExampleExe::~RealIExampleExe()
{
    SysFreeString(m_str);
}

HRESULT STDMETHODCALLTYPE RealIExampleExe::QueryInterface(REFIID riid, void **ppv)
{
    if (IsEqualIID(riid, IID_IUnknown) ||
        IsEqualIID(riid, IID_IDispatch) ||
        IsEqualIID(riid, IID_IExampleExe))
    {
        *ppv = this;
        AddRef();
        return S_OK;
    }

    *ppv = NULL;
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE RealIExampleExe::AddRef()
{
    return ++m_count;
}

ULONG STDMETHODCALLTYPE RealIExampleExe::Release()
{
    --m_count;
    if (m_count == 0)
    {
        delete this;
        InterlockedDecrement(&OutstandingObjects);
        if (CanUnloadNow()) PostMessage(0, WM_QUIT, 0, 0);
        return 0;
    }
    return m_count;
}

HRESULT STDMETHODCALLTYPE RealIExampleExe::SetString(BSTR str)
{
    if (str == NULL) return E_POINTER;
    if (m_str) SysFreeString(m_str);
    m_str = SysAllocStringLen(str, SysStringLen(str));
    if (m_str == NULL) return E_OUTOFMEMORY;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExampleExe::GetString(BSTR *str)
{
    if (str == NULL) return E_POINTER;
    *str = SysAllocStringLen(m_str, SysStringLen(m_str));
    if (*str == NULL) return E_OUTOFMEMORY;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExampleExe::GetTypeInfoCount(UINT *pctinfo)
{
    *pctinfo = 1;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExampleExe::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
    *ppTInfo = NULL;
    if (iTInfo != 0) return DISP_E_BADINDEX;
    if (ExampleExeTypeInfo != NULL)
    {
        ExampleExeTypeInfo->AddRef();
    }
    else
    {
        HRESULT hr = LoadTypeInfo();
        if (FAILED(hr)) return hr;
    }
    *ppTInfo = ExampleExeTypeInfo;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExampleExe::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
    if (ExampleExeTypeInfo == NULL)
    {
        HRESULT hr = LoadTypeInfo();
        if (FAILED(hr)) return hr;
    }

    return DispGetIDsOfNames(ExampleExeTypeInfo, rgszNames, cNames, rgDispId);
}

HRESULT STDMETHODCALLTYPE RealIExampleExe::Invoke(DISPID dispIdMember, REFIID riid,
                                                  LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
                                                  VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
    if (!IsEqualIID(riid, IID_NULL)) return DISP_E_UNKNOWNINTERFACE;

    if (ExampleExeTypeInfo == NULL)
    {
        HRESULT hr = LoadTypeInfo();
        if (FAILED(hr)) return hr;
    }

    return DispInvoke(this, ExampleExeTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}
